﻿import utils

class GxStream(object):
    def __init__(self, data):
        self.data = data
        self.index = 0
        self.end = len(data)
        self.queue = [None]

    def get(self):
        if self.end <= self.index:
            return None
        i = self.index
        length = ord(self.data[i])
        if length == 255: # 헤드의 크기를 맞추기 위해 끝부분에 채워져 있다.
            self.index += 1
            return ""
        self.index += length
        return self.data[i:self.index]

    def fill(self, amount):
        if amount < len(self.queue):
            return
        for i in range(amount - len(self.queue) + 1):
            self.queue.append(self.get())

    def consume(self):
        self.queue.pop(0)

    def LA(self, i):
        self.fill(i)
        return self.queue[i]

    def skip(self, n):
        self.index += n

    def isEnd(self):
        return self.data[self.index] == '\xff'

    def peekNext(self):
        return self.LA(1)

    def nextIsDevice(self):
        next = self.LA(1)
        if next == None or len(next) < 3:
            return False
        return next[1] > '\x80'

    def getNext(self):
        self.consume()
        if self.LA(0) == None:
            raise EndException
        return self.LA(0)

    def getNextCode(self):
        code = self.getNext()
        assert code[0] == chr(len(code)) and code[0] == code[-1]
        return code[1:-1]

    def getNextDevice(self):
        code = self.getNext()
        assert ord(code[0]) == len(code) and code[0] == code[-1]
        address = code[2:-1]
        return ord(code[1]), struct.unpack(numberType[len(address)], address)

    def getDevice(self):
        return GxDevice.fromCode(self)

    def getCommand(self):
        return GxCommand.fromCode(self)

class GxCommandStream(GxStream):
    def __init__(self, filename):
        file.__init__(self, filename, "rb")

    def readbyte(self):
        str = self.read(1)
        if str == "":
            return 0
        return ord(str[0])

    def next(self):
        length = self.readbyte()
        if length == 0:
            return ""
        return chr(length) + self.read(length - 1)

    def readAll(self):
        cmdList = []
        cmd = self.next()
        while cmd != "" and cmd != "\2\2":
            cmdList.append(cmd)
            cmd = self.next()
        return cmdList

    def printData(self, data):
        print InstructionData(data).toString(),

    def printAll(self):
        cmdList = self.readAll()
        for i in cmdList:
            self.printData(i)
            
class GxFile(object):
    pass
    
class EndException(Exception):
    pass

class GxProgramFile(GxFile):

    def loadHead(self, stream):
        print "=== HEAD ==="
        head = GxStream(stream.getNext())
        head.skip(2) # 40 00 - HEAD size
        s = head.getNext()
        while s != "":
            print utils.dump(s)
            s = head.getNext()
        stream.getNext() # 04 00 FF FF

    def loadLine(self, stream):
        if gettype(stream.LA(1)) == 4:
            return GxStatement.fromCode(stream)
        else:
            return GxCommand.fromCode(stream)

    def loadBody(self, stream):
        print "=== BODY ==="
        try:
            while True:
                line = self.loadLine(stream)
                print line
        except EndException:
            #traceback.print_exc()
            pass

    def load(self, filename):
        f = file(filename, "rb")
        stream = GxStream(f.read())
        f.close()

        self.loadHead(stream)
        self.loadBody(stream)

    def dump(self):
        pass

# ============================================================================
#
# ============================================================================

if __name__ == "__main__":
    project = utils.melpath("xxxx")
    program = GxProgramFile()
    program.load(project.program("MAIN"))
    program.dump()


